﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Com.ContentRendering.Api.DataEngine
{
    /// <summary/>
    public class ReflectionCache
    {
        /// <summary/>
        private class NamedProperties
        {
            private Dictionary<string, PropertyInfo> _properties;

            /// <summary/>
            internal NamedProperties()
            {
                this._properties = new Dictionary<string, PropertyInfo>();
            }

            /// <summary/>
            public PropertyInfo this[string name]
            {
                get { return this._properties[name]; }
                set { this._properties[name] = value; }
            }

            /// <summary/>
            internal bool ContainsKey(string name)
            {
                return this._properties.ContainsKey(name);
            }
        }

        private Dictionary<Type, NamedProperties> _namedProperties;
        private Dictionary<Type, PropertyInfo> _indexers;
        private Dictionary<Type, MethodInfo> _indexerKeyMethods;
        private Dictionary<Type, bool> _dictionaryFlag;

        /// <summary/>
        public ReflectionCache()
        {
            this._namedProperties = new Dictionary<Type, NamedProperties>();
            this._indexers = new Dictionary<Type, PropertyInfo>();
            this._indexerKeyMethods = new Dictionary<Type, MethodInfo>();
            this._dictionaryFlag = new Dictionary<Type, bool>();
        }

        /// <summary/>
        internal bool IsPropertyValid(
            Type type, 
            string name)
        {
            // does the type NOT exist
            if (!this._namedProperties.ContainsKey(type))
            {
                return false;
            }

            // does the name exist
            if (!this._namedProperties[type].ContainsKey(name))
            {
                return false;
            }

            // is the proeprty null or not null
            return (this._namedProperties[type][name] != null);
        }

        /// <summary/>
        internal bool IsPropertyCached(
            Type type,
            string name)
        {
            // does the type NOT exist
            if (!this._namedProperties.ContainsKey(type))
            {
                return false;
            }

            // does the name exist
            return this._namedProperties[type].ContainsKey(name);
        }

        /// <summary/>
        internal PropertyInfo FetchProperty(Type type, string name)
        {
            return this._namedProperties[type][name];
        }

        /// <summary/>
        internal void AddProperty(
            Type type,
            string name,
            PropertyInfo propertyInfo)
        {
            // does the type NOT exist
            if (!this._namedProperties.ContainsKey(type))
            {
                this._namedProperties.Add(type, new NamedProperties());
            }

            // add the property
            this._namedProperties[type][name] = propertyInfo;
        }

        /// <summary/>
        internal bool IsIndexerCached(Type type)
        {
            // does the name exist
            return this._indexers.ContainsKey(type);
        }

        /// <summary/>
        internal bool IsIndexerValid(Type type)
        {
            // does the type NOT exist
            if (!this._indexers.ContainsKey(type))
            {
                return false;
            }

            // does the name exist
            return (this._indexers[type] != null);
        }

        /// <summary/>
        internal MethodInfo FetchIndexerKeyMethod(Type type)
        {
            return this._indexerKeyMethods[type];
        }

        /// <summary/>
        internal PropertyInfo FetchIndexer(Type type, string p)
        {
            return this._indexers[type];
        }

        /// <summary/>
        internal void AddIndexer(
            Type type, 
            PropertyInfo propertyInfo)
        {
            this._indexers[type] = propertyInfo;
        }

        /// <summary/>
        internal void AddIndexerKeyMethod(
            Type type, 
            MethodInfo methodInfo)
        {
            this._indexerKeyMethods[type] = methodInfo;
        }

        /// <summary/>
        internal bool IsDictionaryFlagCached(Type type)
        {
            return this._dictionaryFlag.ContainsKey(type);
        }

        /// <summary/>
        internal bool IsDictionaryFlagValid(Type type)
        {
            // does the type NOT exist
            if (!this._dictionaryFlag.ContainsKey(type))
            {
                return false;
            }

            // does the name exist
            return this._dictionaryFlag[type];
        }

        /// <summary/>
        internal void AddDictionaryFlag(
            Type type, 
            bool value)
        {
            this._dictionaryFlag[type] = value;
        }
    }
}
